{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "fallen-score",
   "metadata": {},
   "source": [
    "## Ambassador Notebook Example\n",
    "\n",
    "Assumes\n",
    "\n",
    " * You have installed emissary as per their docs\n",
    " \n",
    " Tested with\n",
    " \n",
    " emissary-ingress-7.3.2 insatlled via [helm](https://www.getambassador.io/docs/emissary/latest/tutorials/getting-started/)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "imperial-playing",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'172.21.255.1'"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "INGRESS_IP=!kubectl get svc emissary-ingress -n emissary -o jsonpath='{.status.loadBalancer.ingress[0].ip}'\n",
    "INGRESS_IP=INGRESS_IP[0]\n",
    "import os\n",
    "os.environ['INGRESS_IP'] = INGRESS_IP\n",
    "INGRESS_IP"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "lesser-equity",
   "metadata": {},
   "source": [
    "### Ambassador Single Model Example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "typical-billy",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "apiVersion: getambassador.io/v3alpha1\r\n",
      "kind: Host\r\n",
      "metadata:\r\n",
      "  name: wildcard\r\n",
      "  namespace: seldon-mesh\r\n",
      "spec:\r\n",
      "  hostname: '*'\r\n",
      "  requestPolicy:\r\n",
      "    insecure:\r\n",
      "      action: Route\r\n",
      "---\r\n",
      "apiVersion: getambassador.io/v3alpha1\r\n",
      "kind: Listener\r\n",
      "metadata:\r\n",
      "  name: emissary-ingress-listener-8080\r\n",
      "  namespace: seldon-mesh\r\n",
      "spec:\r\n",
      "  hostBinding:\r\n",
      "    namespace:\r\n",
      "      from: ALL\r\n",
      "  port: 8080\r\n",
      "  protocol: HTTP\r\n",
      "  securityModel: INSECURE\r\n",
      "---\r\n",
      "apiVersion: getambassador.io/v3alpha1\r\n",
      "kind: Mapping\r\n",
      "metadata:\r\n",
      "  name: iris-grpc\r\n",
      "  namespace: seldon-mesh\r\n",
      "spec:\r\n",
      "  add_request_headers:\r\n",
      "    seldon-model:\r\n",
      "      value: iris\r\n",
      "  grpc: true\r\n",
      "  hostname: '*'\r\n",
      "  prefix: /inference.GRPCInferenceService\r\n",
      "  rewrite: \"\"\r\n",
      "  service: seldon-mesh:80\r\n",
      "---\r\n",
      "apiVersion: getambassador.io/v3alpha1\r\n",
      "kind: Mapping\r\n",
      "metadata:\r\n",
      "  name: iris-http\r\n",
      "  namespace: seldon-mesh\r\n",
      "spec:\r\n",
      "  add_request_headers:\r\n",
      "    seldon-model:\r\n",
      "      value: iris\r\n",
      "  hostname: '*'\r\n",
      "  prefix: /v2/\r\n",
      "  rewrite: \"\"\r\n",
      "  service: seldon-mesh:80\r\n",
      "---\r\n",
      "apiVersion: mlops.seldon.io/v1alpha1\r\n",
      "kind: Model\r\n",
      "metadata:\r\n",
      "  name: iris\r\n",
      "  namespace: seldon-mesh\r\n",
      "spec:\r\n",
      "  requirements:\r\n",
      "  - sklearn\r\n",
      "  storageUri: gs://seldon-models/mlserver/iris\r\n"
     ]
    }
   ],
   "source": [
    "!kustomize build config/single-model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "welsh-tribune",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "host.getambassador.io/wildcard created\n",
      "listener.getambassador.io/emissary-ingress-listener-8080 created\n",
      "mapping.getambassador.io/iris-grpc created\n",
      "mapping.getambassador.io/iris-http created\n",
      "model.mlops.seldon.io/iris created\n"
     ]
    }
   ],
   "source": [
    "!kustomize build config/single-model | kubectl apply --validate=false -f -"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "reverse-pantyhose",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "model.mlops.seldon.io/iris condition met\r\n"
     ]
    }
   ],
   "source": [
    "!kubectl wait --for condition=ready --timeout=300s model --all -n seldon-mesh"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "aquatic-suspect",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "*   Trying 172.21.255.1...\n",
      "* Connected to 172.21.255.1 (172.21.255.1) port 80 (#0)\n",
      "> POST /v2/models/iris/infer HTTP/1.1\n",
      "> Host: 172.21.255.1\n",
      "> User-Agent: curl/7.47.0\n",
      "> Accept: */*\n",
      "> Content-Type: application/json\n",
      "> Content-Length: 94\n",
      "> \n",
      "* upload completely sent off: 94 out of 94 bytes\n",
      "< HTTP/1.1 200 OK\n",
      "< content-length: 196\n",
      "< content-type: application/json\n",
      "< date: Sat, 16 Apr 2022 15:45:43 GMT\n",
      "< server: envoy\n",
      "< x-envoy-upstream-service-time: 792\n",
      "< seldon-route: iris_1\n",
      "< \n",
      "* Connection #0 to host 172.21.255.1 left intact\n",
      "{\"model_name\":\"iris_1\",\"model_version\":\"1\",\"id\":\"72ac79f5-b355-4be3-b8c5-2ebedaa39f60\",\"parameters\":null,\"outputs\":[{\"name\":\"predict\",\"shape\":[1],\"datatype\":\"INT64\",\"parameters\":null,\"data\":[2]}]}"
     ]
    }
   ],
   "source": [
    "!curl -v http://${INGRESS_IP}/v2/models/iris/infer -H \"Content-Type: application/json\"\\\n",
    "        -d '{\"inputs\": [{\"name\": \"predict\", \"shape\": [1, 4], \"datatype\": \"FP32\", \"data\": [[1, 2, 3, 4]]}]}'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "consecutive-active",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\r\n",
      "  \"modelName\": \"iris_1\",\r\n",
      "  \"modelVersion\": \"1\",\r\n",
      "  \"outputs\": [\r\n",
      "    {\r\n",
      "      \"name\": \"predict\",\r\n",
      "      \"datatype\": \"INT64\",\r\n",
      "      \"shape\": [\r\n",
      "        \"1\"\r\n",
      "      ],\r\n",
      "      \"contents\": {\r\n",
      "        \"int64Contents\": [\r\n",
      "          \"2\"\r\n",
      "        ]\r\n",
      "      }\r\n",
      "    }\r\n",
      "  ]\r\n",
      "}\r\n"
     ]
    }
   ],
   "source": [
    "!grpcurl -d '{\"model_name\":\"iris\",\"inputs\":[{\"name\":\"input\",\"contents\":{\"fp32_contents\":[1,2,3,4]},\"datatype\":\"FP32\",\"shape\":[1,4]}]}' \\\n",
    "    -plaintext \\\n",
    "    -import-path ../../apis \\\n",
    "    -proto ../../apis/mlops/v2_dataplane/v2_dataplane.proto \\\n",
    "    ${INGRESS_IP}:80 inference.GRPCInferenceService/ModelInfer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "compound-steel",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "host.getambassador.io \"wildcard\" deleted\n",
      "listener.getambassador.io \"emissary-ingress-listener-8080\" deleted\n",
      "mapping.getambassador.io \"iris-grpc\" deleted\n",
      "mapping.getambassador.io \"iris-http\" deleted\n",
      "model.mlops.seldon.io \"iris\" deleted\n"
     ]
    }
   ],
   "source": [
    "!kustomize build config/single-model | kubectl delete -f -"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "attended-storm",
   "metadata": {},
   "source": [
    "### Traffic Split Two Models\n",
    "\n",
    "***Currently not working due to this [issue](https://github.com/emissary-ingress/emissary/issues/4062)***\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "ahead-samoa",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "apiVersion: getambassador.io/v3alpha1\r\n",
      "kind: Host\r\n",
      "metadata:\r\n",
      "  name: wildcard\r\n",
      "  namespace: seldon-mesh\r\n",
      "spec:\r\n",
      "  hostname: '*'\r\n",
      "  requestPolicy:\r\n",
      "    insecure:\r\n",
      "      action: Route\r\n",
      "---\r\n",
      "apiVersion: getambassador.io/v3alpha1\r\n",
      "kind: Listener\r\n",
      "metadata:\r\n",
      "  name: emissary-ingress-listener-8080\r\n",
      "  namespace: seldon-mesh\r\n",
      "spec:\r\n",
      "  hostBinding:\r\n",
      "    namespace:\r\n",
      "      from: ALL\r\n",
      "  port: 8080\r\n",
      "  protocol: HTTP\r\n",
      "  securityModel: INSECURE\r\n",
      "---\r\n",
      "apiVersion: getambassador.io/v3alpha1\r\n",
      "kind: Mapping\r\n",
      "metadata:\r\n",
      "  name: iris1-grpc\r\n",
      "  namespace: seldon-mesh\r\n",
      "spec:\r\n",
      "  add_request_headers:\r\n",
      "    seldon-model:\r\n",
      "      value: iris1\r\n",
      "  grpc: true\r\n",
      "  hostname: '*'\r\n",
      "  prefix: /inference.GRPCInferenceService\r\n",
      "  rewrite: \"\"\r\n",
      "  service: seldon-mesh:80\r\n",
      "---\r\n",
      "apiVersion: getambassador.io/v3alpha1\r\n",
      "kind: Mapping\r\n",
      "metadata:\r\n",
      "  name: iris1-http\r\n",
      "  namespace: seldon-mesh\r\n",
      "spec:\r\n",
      "  add_request_headers:\r\n",
      "    seldon-model:\r\n",
      "      value: iris1\r\n",
      "  add_response_headers:\r\n",
      "    seldon_model:\r\n",
      "      value: iris1\r\n",
      "  hostname: '*'\r\n",
      "  prefix: /v2\r\n",
      "  rewrite: \"\"\r\n",
      "  service: seldon-mesh:80\r\n",
      "---\r\n",
      "apiVersion: getambassador.io/v3alpha1\r\n",
      "kind: Mapping\r\n",
      "metadata:\r\n",
      "  name: iris2-grpc\r\n",
      "  namespace: seldon-mesh\r\n",
      "spec:\r\n",
      "  add_request_headers:\r\n",
      "    seldon-model:\r\n",
      "      value: iris2\r\n",
      "  grpc: true\r\n",
      "  hostname: '*'\r\n",
      "  prefix: /inference.GRPCInferenceService\r\n",
      "  rewrite: \"\"\r\n",
      "  service: seldon-mesh:80\r\n",
      "  weight: 50\r\n",
      "---\r\n",
      "apiVersion: getambassador.io/v3alpha1\r\n",
      "kind: Mapping\r\n",
      "metadata:\r\n",
      "  name: iris2-http\r\n",
      "  namespace: seldon-mesh\r\n",
      "spec:\r\n",
      "  add_request_headers:\r\n",
      "    seldon-model:\r\n",
      "      value: iris2\r\n",
      "  add_response_headers:\r\n",
      "    seldon_model:\r\n",
      "      value: iris2\r\n",
      "  hostname: '*'\r\n",
      "  prefix: /v2\r\n",
      "  rewrite: \"\"\r\n",
      "  service: seldon-mesh:80\r\n",
      "  weight: 50\r\n",
      "---\r\n",
      "apiVersion: mlops.seldon.io/v1alpha1\r\n",
      "kind: Model\r\n",
      "metadata:\r\n",
      "  name: iris1\r\n",
      "  namespace: seldon-mesh\r\n",
      "spec:\r\n",
      "  requirements:\r\n",
      "  - sklearn\r\n",
      "  storageUri: gs://seldon-models/mlserver/iris\r\n",
      "---\r\n",
      "apiVersion: mlops.seldon.io/v1alpha1\r\n",
      "kind: Model\r\n",
      "metadata:\r\n",
      "  name: iris2\r\n",
      "  namespace: seldon-mesh\r\n",
      "spec:\r\n",
      "  requirements:\r\n",
      "  - sklearn\r\n",
      "  storageUri: gs://seldon-models/mlserver/iris\r\n"
     ]
    }
   ],
   "source": [
    "!kustomize build config/traffic-split"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "comprehensive-guide",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "host.getambassador.io/wildcard created\n",
      "listener.getambassador.io/emissary-ingress-listener-8080 created\n",
      "mapping.getambassador.io/iris1-grpc created\n",
      "mapping.getambassador.io/iris1-http created\n",
      "mapping.getambassador.io/iris2-grpc created\n",
      "mapping.getambassador.io/iris2-http created\n",
      "model.mlops.seldon.io/iris1 created\n",
      "model.mlops.seldon.io/iris2 created\n"
     ]
    }
   ],
   "source": [
    "!kustomize build config/traffic-split | kubectl apply -f -"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "explicit-plasma",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "model.mlops.seldon.io/iris1 condition met\r\n",
      "model.mlops.seldon.io/iris2 condition met\r\n"
     ]
    }
   ],
   "source": [
    "!kubectl wait --for condition=ready --timeout=300s model --all -n seldon-mesh"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "organizational-spokesman",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "*   Trying 172.21.255.1...\n",
      "* Connected to 172.21.255.1 (172.21.255.1) port 80 (#0)\n",
      "> POST /v2/models/iris/infer HTTP/1.1\n",
      "> Host: 172.21.255.1\n",
      "> User-Agent: curl/7.47.0\n",
      "> Accept: */*\n",
      "> Content-Type: application/json\n",
      "> Content-Length: 94\n",
      "> \n",
      "* upload completely sent off: 94 out of 94 bytes\n",
      "< HTTP/1.1 200 OK\n",
      "< content-length: 197\n",
      "< content-type: application/json\n",
      "< date: Sat, 16 Apr 2022 15:46:17 GMT\n",
      "< server: envoy\n",
      "< x-envoy-upstream-service-time: 920\n",
      "< seldon-route: iris2_1\n",
      "< seldon_model: iris2\n",
      "< \n",
      "* Connection #0 to host 172.21.255.1 left intact\n",
      "{\"model_name\":\"iris2_1\",\"model_version\":\"1\",\"id\":\"ed521c32-cd85-4cb8-90eb-7c896803f271\",\"parameters\":null,\"outputs\":[{\"name\":\"predict\",\"shape\":[1],\"datatype\":\"INT64\",\"parameters\":null,\"data\":[2]}]}"
     ]
    }
   ],
   "source": [
    "!curl -v http://${INGRESS_IP}/v2/models/iris/infer -H \"Content-Type: application/json\" \\\n",
    "        -d '{\"inputs\": [{\"name\": \"predict\", \"shape\": [1, 4], \"datatype\": \"FP32\", \"data\": [[1, 2, 3, 4]]}]}'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "thorough-surgery",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\r\n",
      "  \"modelName\": \"iris2_1\",\r\n",
      "  \"modelVersion\": \"1\",\r\n",
      "  \"outputs\": [\r\n",
      "    {\r\n",
      "      \"name\": \"predict\",\r\n",
      "      \"datatype\": \"INT64\",\r\n",
      "      \"shape\": [\r\n",
      "        \"1\"\r\n",
      "      ],\r\n",
      "      \"contents\": {\r\n",
      "        \"int64Contents\": [\r\n",
      "          \"2\"\r\n",
      "        ]\r\n",
      "      }\r\n",
      "    }\r\n",
      "  ]\r\n",
      "}\r\n"
     ]
    }
   ],
   "source": [
    "!grpcurl -d '{\"model_name\":\"iris1\",\"inputs\":[{\"name\":\"input\",\"contents\":{\"fp32_contents\":[1,2,3,4]},\"datatype\":\"FP32\",\"shape\":[1,4]}]}' \\\n",
    "    -plaintext \\\n",
    "    -import-path ../../apis \\\n",
    "    -proto ../../apis/mlops/v2_dataplane/v2_dataplane.proto \\\n",
    "    ${INGRESS_IP}:80 inference.GRPCInferenceService/ModelInfer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "mechanical-diagnosis",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "host.getambassador.io \"wildcard\" deleted\n",
      "listener.getambassador.io \"emissary-ingress-listener-8080\" deleted\n",
      "mapping.getambassador.io \"iris1-grpc\" deleted\n",
      "mapping.getambassador.io \"iris1-http\" deleted\n",
      "mapping.getambassador.io \"iris2-grpc\" deleted\n",
      "mapping.getambassador.io \"iris2-http\" deleted\n",
      "model.mlops.seldon.io \"iris1\" deleted\n",
      "model.mlops.seldon.io \"iris2\" deleted\n"
     ]
    }
   ],
   "source": [
    "!kustomize build config/traffic-split | kubectl delete -f -"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
